#pragma once
#include <iostream>
#include <string>
#include <unistd.h>
#include <queue>
#include <pthread.h>
#include "Mutex.hpp"
#include "Sem.hpp"
using namespace std;
using namespace ve;
using namespace sem_module;

static const int gcap = 5; // 最大容量

template <class t>
class ringqueue
{
private:
    vector<t> _rq;
    int _cap;

    Sem _blank_sem;//生产者需要的空位子
    int _p_step;

    Sem _data_sem;//消费者需要数据资源
    int _c_step;

    //维护多生产多消费需要两把锁
    Mutex _plock;
    Mutex _clock;
public:
    ringqueue(int cap=gcap):_rq(cap),_cap(gcap),_p_step(0),_c_step(0),_blank_sem(cap),_data_sem(0)
    {
    }
    ~ringqueue()
    {
    }
    void equeue(const t &in)//生产者
    {
        //1.申请信号量,空位置信号量-1,对于多线程来说，可以先申请信号量资源再进行锁的竞争，因为如果先申请锁然后发现信号量已经没了，那么这个线程就会持有锁很久，这是我们不希望看到的，我们希望持有锁的时间越短越好。
        _blank_sem.p();
        //加锁
        _plock.lock();
        //2.生产
        _rq[_p_step]=in;
        //3.更新下标
        _p_step++;
        _p_step%=_cap;
        //开锁
        _plock.unlock();
        //4.增加数据量，数据信号量+1
        _data_sem.v();
    }
    void pop(t* out)//消费者
    {
        //1.申请数据信号量，数据信号量-1
        _data_sem.p();
        //加锁
        _clock.lock();
        //2.消费
        *out=_rq[_c_step];
        //3.更新下标
        _c_step++;
        _c_step%=_cap;
        //开锁
        _clock.unlock();
        //4.增加空位置信号量
        _blank_sem.v(); 
    }
};